package com.yami.shop.search.api.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.yami.shop.bean.enums.ProdType;
import com.yami.shop.bean.event.EsProductActivityInfoEvent;
import com.yami.shop.bean.param.EsProductParam;
import com.yami.shop.bean.vo.search.EsProductSearchVO;
import com.yami.shop.bean.vo.search.ProductSearchVO;
import com.yami.shop.common.constants.CacheNames;
import com.yami.shop.common.constants.EsCacheNames;
import com.yami.shop.common.enums.EsRenovationProductSortEnum;
import com.yami.shop.common.response.ServerResponseEntity;
import com.yami.shop.common.util.EsPageVO;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.search.common.manager.ProductSearchManager;
import com.yami.shop.search.common.param.EsPageParam;
import com.yami.shop.search.common.service.SearchProductService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


/**
 * 商品搜索
 * @author FrozenWatermelon
 * @date 2020/11/16
 */
@RestController("appSearchSpuController")
@RequestMapping("/search")
@Tag(name = "商品搜索接口")
public class ProductSearchController {

    @Autowired
    private SearchProductService searchProductService;
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    @Autowired
    private ProductSearchManager productSearchManager;

    @GetMapping("/page")
    @Operation(summary =  "商品搜索接口（仅商品信息）", description = "商品搜索接口")
    public ServerResponseEntity<EsPageVO<EsProductSearchVO>> page(@Valid EsPageParam pageParam,@ParameterObject EsProductParam productParam) {
        productParam.setIndexIdPrefix("prod");
        loadSearchProdType(productParam);
        EsPageVO<EsProductSearchVO> esProductSearchEsPage = simplePage(pageParam, productParam);
        return ServerResponseEntity.success(esProductSearchEsPage);
    }

    @GetMapping("/pageAndAggregation")
    @Operation(summary = "商品及商品的分类、品牌信息接口" , description = "商品及商品的分类、品牌信息接口")
    public ServerResponseEntity<EsPageVO<EsProductSearchVO>> pageAndAggregation(@Valid EsPageParam pageParam,@ParameterObject EsProductParam productParam) {
        productParam.setIndexIdPrefix("prod");
        loadSearchProdType(productParam);
        EsPageVO<EsProductSearchVO> esProductSearchEsPage = searchPageAndAggregation(pageParam, productParam);
        return ServerResponseEntity.success(esProductSearchEsPage);
    }

    @GetMapping("/renovationPage")
    @Operation(summary =  "商品信息列表(装修商品列表)", description = "商品信息列表(装修商品列表)")
    public ServerResponseEntity<EsPageVO<ProductSearchVO>> renovationPage(@Valid EsPageParam pageParam,@ParameterObject EsProductParam productParam) {
        productParam.setIndexIdPrefix("prod");
        Long size = null;
        if(Objects.equals(productParam.getShowSpuType(),1)){
            if(Objects.equals(productParam.getEsRenovationSpuSort(), EsRenovationProductSortEnum.CREATE_TIME_ASC.value()) || Objects.equals(productParam.getEsRenovationSpuSort(),EsRenovationProductSortEnum.CREATE_TIME_DESC.value())){
                productParam.setSort(productParam.getEsRenovationSpuSort());
            }else {
                // 获取指定规则的商品ids
                size = getSpuIds(pageParam, productParam);
            }
        }
        EsPageVO<ProductSearchVO> searchPage = searchProductService.renovationPage(pageParam, productParam, size);
        if (CollectionUtil.isEmpty(searchPage.getRecords())) {
            return ServerResponseEntity.success(searchPage);
        }
        // 如果包含秒杀、团购活动商品，就插入活动信息
        long count = searchPage.getRecords().stream().filter(product -> Objects.equals(product.getProdType(), ProdType.PROD_TYPE_GROUP.value()) || Objects.equals(product.getProdType(), ProdType.PROD_TYPE_SECKILL.value())).count();
        if (count > 0) {
            eventPublisher.publishEvent(new EsProductActivityInfoEvent(productParam.getProdType(), searchPage.getRecords()));
        }
        return ServerResponseEntity.success(searchPage);
    }

    private Long getSpuIds(EsPageParam pageParam, EsProductParam productParam) {
        Long shopId = Objects.isNull(productParam.getShopId()) ? 0L :  productParam.getShopId();
        String key = EsCacheNames.RENOVATION_PRODUCT_IDS_CACHE + CacheNames.UNION + shopId +
                CacheNames.UNION_KEY + productParam.getEsTimeRange() + CacheNames.UNION_KEY + productParam.getEsRenovationSpuSort();
        if(!RedisUtil.hasKey(key)){
            productSearchManager.addRenovationSpuCache(key,productParam,shopId, EsCacheNames.RENOVATION_PRODUCT_IDS_CACHE_TIME);
        }
        Long size = RedisUtil.getListSize(key);
        long startNum = (long) (pageParam.getCurrent() - 1) * pageParam.getSize();
        long endNum = (long) pageParam.getCurrent() * pageParam.getSize() - 1;
        endNum = Math.min(endNum,size);
        List prodIds = RedisUtil.getListRange(key, startNum, endNum);
        productParam.setProdIds(prodIds);
        return size;
    }
    /**
     * 该方法只进行商品查询,不要添加任何聚合相关的代码降低查询效率，如果需要聚合请使用searchPageAndAggregation()
     * @param pageParam
     * @param productParam
     * @return
     */
    private EsPageVO<EsProductSearchVO> simplePage(EsPageParam pageParam, EsProductParam productParam) {
        loadSearchProdType(productParam);
        EsPageVO<EsProductSearchVO> searchPage =  searchProductService.page(pageParam, productParam, Boolean.FALSE);
        loadData(productParam, searchPage.getRecords());
        return searchPage;
    }

    public EsPageVO<EsProductSearchVO> searchPageAndAggregation(EsPageParam pageParam, EsProductParam productParam) {
        loadSearchProdType(productParam);
        EsPageVO<EsProductSearchVO> searchPage =  searchProductService.page(pageParam, productParam, Boolean.FALSE);
        loadData(productParam, searchPage.getRecords());
        EsProductSearchVO searchExtension = searchProductService.searchExtension(pageParam, productParam);
        EsProductSearchVO productSearchVO = searchPage.getRecords().get(0);
        productSearchVO.setBrands(searchExtension.getBrands());
        productSearchVO.setCategories(searchExtension.getCategories());
        productSearchVO.setShopInfo(searchExtension.getShopInfo());
        return searchPage;
    }

    /**
     * 处理搜索数据
     * @param productParam
     * @param list
     */
    private void loadData(EsProductParam productParam, List<EsProductSearchVO> list) {
        if (CollUtil.isEmpty(list)) {
            return;
        }
        for (EsProductSearchVO productSearchVO : list) {
            // 如果包含秒杀、团购活动商品，就插入活动信息
            if (containActivityProd(productSearchVO)) {
                eventPublisher.publishEvent(new EsProductActivityInfoEvent(productParam.getProdType(), productSearchVO.getProducts()));
            }
        }
    }

    private boolean containActivityProd(EsProductSearchVO productSearchVO) {
        if (CollUtil.isEmpty(productSearchVO.getProducts())) {
            return Boolean.FALSE;
        }
        long count = productSearchVO.getProducts().stream().filter(product -> Objects.equals(product.getProdType(), ProdType.PROD_TYPE_GROUP.value()) || Objects.equals(product.getProdType(), ProdType.PROD_TYPE_SECKILL.value())).count();
        return count > 0;
    }

    private void loadSearchProdType(EsProductParam productParam) {
        // 用户端没有搜索全部商品需求， 当不指定商品类型时默认为非积分商品和活动商品
        if (Objects.isNull(productParam.getProdType())) {
            List<Integer> prodTypeList = new ArrayList<>();
            prodTypeList.add(ProdType.PROD_TYPE_SCORE.value());
            prodTypeList.add(ProdType.PROD_TYPE_ACTIVE.value());
            productParam.setMustNotProdTypes(prodTypeList);
        }
    }
}
